# -*- coding: utf-8 -*-
# @Time    : 2024/6/27 17:42
# @Author  : yujiahao
# @File    : 22_pandas_notices.py
# @description:Pandas使用的注意事项、与NumPy比较


'''

Pandas 是在 NumPy 的基础构建而来，因此，熟悉 NumPy 可以更加有效的帮助我们使用 Pandas。

NumPy 主要用 C语言编写，因此，在计算还和处理一维或多维数组方面，它要比 Python 数组快得多。关于 NumPy 的学习，可以参考 https://c.biancheng.net/numpy/。

因此，当您在使用 Pandas 时，需要额外留意一些事项，避免出现一些不必要的错误。
'''
import numpy as np
import array

import pandas as pd


# todo 1、Pandas和NumPy的比较
def pandas_numpy_compare():
    # todo 1.1、创建数组
    '''数组的主要作用是在一个变量中存储多个值。NumPy 可以轻松地处理多维数组。'''

    arr = np.array([2, 4, 6, 8, 10, 12])
    print(type(arr))
    print("打印新建数组: ", end="")
    # 使用for循环读取数据
    for l in range(0, 5):
        print(arr[l], end=" ")

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    '''虽然 Python 本身没有数组这个说法，不过 Python 提供一个 array 模块，用于创建数字、字符类型的数组，它能够容纳字符型、整型、浮点型等基本类型。'''

    # 注意此处的 'l' 表示有符号int类型
    arr = array.array('l', [2, 4, 6, 8, 10, 12])
    print(type(arr))
    print("新建数组: ", end="")
    # print 函数的 end 参数用于指定输出结束时的字符，默认情况下是换行符 \n。
    for i in range(0, 5):
        print(arr[i], end=" ")

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # todo 1.2、布尔索引
    '''布尔索引是 NumPy 的重要特性之一，通常与 Pandas 一起使用。它的主要作用是过滤 DataFrame 中的数据，比如布尔值的掩码操作。'''

    dict = {'name': ["Smith", "William", "Phill", "Parker"],
            'age': ["28", "39", "34", "36"]}
    info = pd.DataFrame(dict, index=[True, True, False, True])
    print(info)
    # 返回所有为 True的数据
    print('\n返回所有为 True的数据\n', info.loc[True])

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # todo 1.3、 重塑数组形状

    '''在不改变数组数据的情况下，对数组进行变形操作，即改变数组的维度，比如 2*3（两行三列）的二维数组变维 3*2（三行两列）的二维数组。变形操作可以通过 reshape() 函数实现。
    
    原数组:
        [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15]
        
    变形后数组:
        [[ 0  1  2  3  4  5  6  7]
        [ 8  9 10 11 12 13 14 15]]
        
    变形后数组:
        [[ 0  1]
        [ 2  3]
        [ 4  5]
        [ 6  7]
        [ 8  9]
        [10 11]
        [12 13]
        [14 15]]
    
    '''
    arr = np.arange(16)
    print("原数组: \n", arr)
    arr = np.arange(16).reshape(2, 8)
    print("\n变形后数组:\n", arr)
    arr = np.arange(16).reshape(8, 2)
    print("\n变形后数组:\n", arr)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # todo 1.4、 Pdans与NumPy区别
    """
    Pandas 和 NumPy 被认为是科学计算与机器学习中必不可少的库，因为它们具有直观的语法和高性能的矩阵计算能力。
    下面对 Pandas 与 NumPy 进行简单的总结，如下表所示：
    
    比较项        Pandas                                        NumPy
    适应性        Pandas主要用来处理类表格数据。                    NumPy 主要用来处理数值数据。
    工具          Pandas提供了Series和DataFrame数据结构。          NumPy 构建了 ndarray array来容纳数据。
    性能          Pandas对于处理50万行以上的数据更具优势。           NumPy 则对于50万以下或者更少的数据，性能更佳。
    内存利用率    与 NumPy相比，Pandas会消耗大量的内存。             NumPy 会消耗较少的内存。
    对象          Pandas 提供了 DataFrame 2D数据表对象。           NumPy 则提供了一个多维数组 ndarray 对象。
    """

    # todo 1.5、 转换ndarray数组
    '''
    在某些情况下，需要执行一些 NumPy 数值计算的高级函数，这个时候您可以使用 to_numpy() 函数，将 DataFrame 对象转换为 NumPy ndarray 数组，并将其返回。
        函数的语法格式如下：
            DataFrame.to_numpy(dtype=None, copy=False)   
        
        参数说明如下：
            dtype：可选参数，表示数据类型；
            copy：布尔值参数，默认值为 Fales，表示返回值不是其他数组的视图。
    '''

    info = pd.DataFrame({"P": [2, 3], "Q": [4.0, 5.8]})
    # 给info添加R列
    info['R'] = pd.date_range('2020-12-23', periods=2)
    print(info)
    # 将其转化为numpy数组
    n = info.to_numpy()

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    print(n)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    print(type(n))

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 创建DataFrame对象
    info = pd.DataFrame([[17, 62, 35], [25, 36, 54], [42, 20, 15], [48, 62, 76]],
                        columns=['x', 'y', 'z'])
    print('DataFrame\n----------\n', info)
    # 转换DataFrame为数组array
    arr = info.to_numpy()

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    print('\nNumpy Array\n----------\n', arr)


# todo 2、Pandas使用的注意事项
def pandas_notices():
    # todo 2.1、if语句使用
    '''在 if 语句中，如果您需要将 Pandas 对象转换为布尔值时，需要格外留意，这种操作会引起  ValueError 异常.

    从输出结果可以看出，代码引发了 ValueError 错误，并告诉我们 Series 的真值是不明确的。下面对其进行了简单分析：

        如果 if 语句判断为 True，可能是认为它的长度并不是 0，反之 if 语句判断为 Fasle，
        可能是认为 Series 的数据值中包含了 False 值，因此是真还是假，无法判断，所以此处抛出了 ValueError 错误。

    '''
    try:
        if pd.Series([False, True, False]):
            print('I am False')
    except ValueError:
        print(ValueError)

    # 使用 any()方法解决
    if pd.Series([False, True, False]).any():
        print("I am ，what i am")

    # 如果要是计算单个布尔元素的 Series 对象，那么可以使用 bool() 方法进行修改，说白了就是指定类型：
    print(pd.Series([False]).bool())

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # todo 2.2、布尔运算
    '''如果在 Pandas 对象中使用==（相等）和!=（不相等） 这样的布尔运算符时，将返回一个布尔序列'''
    s = pd.Series(range(4))
    # 返回布尔值序列，行索引为3的位置为True
    print('返回布尔值序列，行索引为3的位置为True\n', s == 13)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # todo 2.3、isin()操作
    '''
    isin() 也会返回一个布尔序列，它用来判断元素值是否包含在的 Series 序列中。
        第一个元素 'a' 在列表 ['a', 'c', 'e'] 中，所以对应位置为 True。
        第二个元素 'b' 不在列表 ['a', 'c', 'e'] 中，所以对应位置为 False。
        第三个元素 'c' 在列表 ['a', 'c', 'e'] 中，所以对应位置为 True。
    总结
        isin() 方法非常有用，可以用于过滤数据或进行条件选择。
        它返回一个布尔序列，可以直接用于布尔索引来选择满足条件的元素。
    
    '''
    s = pd.Series(list('abc'))
    s = s.isin(['a', 'c', 'e'])
    print(s)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # todo 2.4、 reindex()操作
    '''reindex() 函数表示重置行索引，该方法会生成新的 Pandas 对象,提取的对象索引还是原索引'''
    # index行索引使用字符和数字混合的形式
    df = pd.DataFrame(np.random.randn(6, 4), columns=['one', 'two', 'three', 'four'], index=['a', 'b', 2, 3, 'e', 5])

    print(df)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 数字与字符混合后取数据
    print(df.reindex(['a', 'b', 5]))

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    print(df.reindex([2, 'e']))


def main():
    # pandas_numpy_compare()
    pandas_notices()


if __name__ == '__main__':
    main()
